﻿using RAP.Framework.Libary.Utils;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using static RAP.Framework.Libary.DataSource.ServiceUtils;
using System.Linq;
using System.Collections;
using RAP.Framework.Libary.Utils.Collection.Iterator;
using System.Collections.Specialized;
using DynamicExpresso;

namespace RAP.Framework.Libary.SqlTaskParser.Parsers
{
	/// <summary>
	/// 继承自ExpressionTokenParser，@join指令必须等待前面的查询任务执行完毕后再执行
	/// @join解析器，将指定的两个结果集按指定方式和条件进行链接并返回指定字段的值（@join (resultAlias:ResultTypeName) select a.id, a.order_no as orderNO, b.name as bName from userOrders.Goods as a + goods as b on a.goodId = b.id）
	/// a - b 一对一链接
	/// a + b 一对多链接
	/// </summary>
	public class JoinTokenParser : ExpressionTokenParser
	{
		protected const string SYNTAX_ERROR_PREFIX = "@join 语法错误，";

		protected class DataSource
		{
			public string Expression { get; set; }
			public string Alias { get; set; }
		}

		protected class SelectField
		{
			public string DataSource { get; set; }
			public string Field { get; set; }
			public string Alias { get; set; }
			public bool IsConst { get; set; }
			public object ConstValue { get; set; }
		}

		protected virtual DataSource ParseDataSourceExpression( string exp )
		{
			var arr = exp.Split( new string[] { AS_SYNTAX } );
			var dataSource = string.Empty;
			var alias = string.Empty;
			dataSource = arr.FirstItem();
			if ( arr.Length > 1 )
			{
				alias = arr.Last<string>()?.Trim();
			}
			else
			{
				alias = arr.FirstItem().Split( '.' ).Last<string>()?.Trim();
			}
			return new DataSource
			{
				Expression = dataSource,
				Alias = alias
			};
		}

		protected virtual IList<SelectField> ParseSelectFields( string selectExp )
		{
			if ( selectExp.IsNullOrEmpty() )
			{
				return null;
			}
			var selectFields = new List<SelectField>();
			foreach ( var field in selectExp.Trim().Split( ',' ) )
			{
				var arr = field.Trim().Split( new string[] { AS_SYNTAX } );
				var fieldName = arr.FirstItem().RightEndString( '.' ).Trim();
				var alias = fieldName != "*" ? fieldName : null;
				var dataSource = field.LeftSubstring( '.' ).Trim();

				if ( arr.Length > 1 )
				{
					alias = arr.Last<string>()?.Trim();
				}
				selectFields.Add( new SelectField
				{
					DataSource = dataSource,
					Field = fieldName,
					Alias = alias
				} );
			}
			return selectFields;
		}

		public override void ParseToken( SqlParseContext parseContext )
		{
			this.DoAwait( parseContext );
			var token = parseContext.CurrentToken;
			var tokenParam = token.Param?.Trim();
			if ( tokenParam.IsNullOrEmpty() )
			{
				return;
			}
			parseContext.CurrentTask.OnSuccess( ( task, parseResult, context ) =>
			{
				//任务执行成功后执行数据链接
				//获取结果集别名以及结果模型类型描述
				var resultAliasExp = tokenParam.PickSubstring( '(', ')', out tokenParam ).Trim();
				if ( resultAliasExp.IsNullOrEmpty() )
				{
					throw new NullReferenceException( $"{SYNTAX_ERROR_PREFIX}缺少符号 '('。" );
				}
				var resultAlias = new
				{
					Alias = resultAliasExp.LeftSubstring( ':' ),
					ResultTypeName = resultAliasExp.RightEndString( ':', "map" )//默认键值对
				};
				if ( resultAlias.Alias.IsNullOrEmpty() )
				{
					throw new NullReferenceException( $"{SYNTAX_ERROR_PREFIX}结果集未定义别名。" );
				}

				//获取select表达式
				var selectExp = tokenParam.PickSubstring( " select ", " from ", out tokenParam ).Trim();

				if ( selectExp.IsNullOrEmpty() )
				{
					throw new NullReferenceException( $"{SYNTAX_ERROR_PREFIX}缺少 'select'/'from' 关键字。" );
				}
				var interpreter = new Interpreter();
				var selectFields = ParseSelectFields( selectExp );
				if ( selectFields.IsNullOrEmpty() )
				{
					throw new NullReferenceException( $"{SYNTAX_ERROR_PREFIX}'select' 缺少字段定义。" );
				}
				var tokenParamValues = tokenParam.Split( new string[] { " on " } );
				if ( tokenParamValues.IsNullOrEmpty() )
				{
					throw new NullReferenceException( $"{SYNTAX_ERROR_PREFIX}缺少关键字 'on'。" );
				}
				var dataSourceExp = tokenParamValues.FirstItem()?.Split( '+', '-' );
				if ( dataSourceExp.IsNullOrEmpty() || dataSourceExp.Length < 2 )
				{
					throw new NullReferenceException( $"{SYNTAX_ERROR_PREFIX}缺少数据源定义或数据源链接符号 '+'/'-'。" );
				}
				var isOneToMany = tokenParamValues.FirstItem()?.IndexOf( '+' ) > 0;//是否一对多关系，否则一对一
				var joinConditionExp = ParseCSharpExpression( tokenParamValues.Last<string>() );
				var dataSourceA = ParseDataSourceExpression( dataSourceExp.FirstItem() );
				var dataSourceB = ParseDataSourceExpression( dataSourceExp.Last<string>() );
				var results = context.ToDictionary( RESULT_FIELD );
				if ( results == null )
				{
					return;
				}
				try
				{
					var dataSourceAData = new RecursionIterator<object>( results, dataSourceA.Expression );
					var dataSourceBData = new RecursionIterator<object>( results, dataSourceB.Expression );
					//创建数据模型实例
					Lambda joinHandler = null;

					//创建数据模型
					object CreateDataModel( string resultTypeName, object sourceDataA, object sourceDataB )
					{
						var properties = new ListDictionary();
						foreach ( var selectField in selectFields )
						{
							object dataSource = null;
							if ( !selectField.IsConst )
							{
								if ( selectField.DataSource == dataSourceA.Alias )
								{
									dataSource = sourceDataA;
								}
								else if ( selectField.DataSource == dataSourceB.Alias )
								{
									dataSource = sourceDataB;
								}
								if ( selectField.Field != "*" )
								{
									properties[ selectField.Alias ] = dataSource.GetValue( selectField.Field );
								}
								else
								{
									if ( selectField.Alias.IsNotNullOrEmpty() )
									{
										properties[ selectField.Alias ] = dataSource;
									}
									else
									{
										dataSource.GetValues().CopyTo( properties );
									}
								}
							}
							else
							{
								//否则为常量
								properties[ selectField.Alias ] = selectField.ConstValue;
							}
						}
						return parseResult.CreateDataModel( resultTypeName, properties );
					};

					//检测是否满足链接条件
					bool joinTest( object dataA, object dataB )
					{
						if ( joinHandler == null )
						{
							joinHandler = interpreter.Parse
							(
								joinConditionExp,
								new Parameter( dataSourceA.Alias, dataA?.GetType() ),
								new Parameter( dataSourceB.Alias, dataB?.GetType() )
							);
						}
						return joinHandler.Invoke( dataA, dataB ).Equals( true );
					};
					var joinResultList = new ArrayList();
					foreach ( var itemA in dataSourceAData )
					{
						foreach ( var itemB in dataSourceBData )
						{
							//检测是否满足链接条件
							if ( joinTest( itemA.Value, itemB.Value ) )
							{
								//如果满足链接条件
								var data = CreateDataModel( resultAlias.ResultTypeName, itemA.Value, itemB.Value );
								joinResultList.Add( data );
								if ( !isOneToMany )
								{
									//如果是一对一，则退出当前迭代
									break;
								}
							}
						}
					}
					results[ resultAlias.Alias ] = joinResultList;
				}
				catch ( Exception ex )
				{
					throw new Exception( $"表达式[{joinConditionExp}]语法错误！\r\n错误信息：{ex.Message}" );
				}
			} );
		}
	}
}
